package com.ykdl.member.kid.image;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import org.apache.http.client.ClientProtocolException;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.util.Log;

import com.ykdl.member.KidApp;
import com.ykdl.member.constant.KidConfig;
import com.ykdl.member.http.HttpUtil;
import com.ykdl.member.kid.util.MD5;
import com.ykdl.member.kid.util.SysUtil;
/**
 * 新的加载图片的工具类
 * @see
 * @since 1.0
 */
public class ImageLoader {
	public static final String TAG = "ImageLoader";
	public static final String GLOBAL_ACTIVITY = "global";
	private Map<String, List<ImageRequest>> mRequests = new HashMap<String, List<ImageRequest>>();
	private ImageRequest mCurrentRequest;
	private String mCurrentActivity;
	private ImageCache mImageCache;
	private boolean mRunning = false;
	private Object mLock = new Object();
	private Thread mThread;
	private static final ImageLoader mInstance = new ImageLoader();

	private ImageLoader() {
		mImageCache = new ImageCache();
	}

	public static ImageLoader getInstance() {
		return mInstance;
	}

	public ImageCache getImageCache() {
		return mImageCache;
	}

	public String getCurrentActivity() {
		return mCurrentActivity;
	}

	private Runnable mWork = new Runnable() {
		@Override
		public void run() {
			ImageRequest request = null;
			TagObject firstTag = null;
			Bitmap image = null;
			String activity = null;
			boolean wait;
			while (true) {
				wait = false;
				image = null;
				synchronized (ImageLoader.this) {
					activity = GLOBAL_ACTIVITY;
					while (true) {
						List<ImageRequest> requests = mRequests.get(activity);
						if (requests != null && requests.size() > 0) {
							request = requests.get(0);
							if (request.objs != null && request.objs.length > 0) {
								firstTag = request.objs[0];
							} else {
								firstTag = null;
							}
							requests.remove(0);
							break;
						} else {
							if (GLOBAL_ACTIVITY.equals(activity)) {
								activity = mCurrentActivity;
							} else {
								if (requests != null) {
									mRequests.remove(activity);
								}
								wait = true;
							}
							if (activity == null) {
								wait = true;
							}
							if (wait) {
								mRunning = false;
								break;
							}
						}
					}
				}

				if (wait) {
					synchronized (mLock) {
						try {
							mLock.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						mRunning = true;
					}
					continue;
				}

				try {
					synchronized (mImageCache) {
						image = mImageCache.getImage(request.url,
								firstTag != null ? firstTag.options : null,
								request.activity);
					}
				} catch (Exception e) {
				}
				if (image == null) {
					HttpURLConnection connection = null;
					ByteArrayOutputStream output = null;
					try {
						connection = getConnection(request.url);
						connection.setConnectTimeout(30 * 1000);
						connection.setReadTimeout(30 * 1000);
						InputStream is = connection.getInputStream();
						connection.connect();
						int responseCode = connection.getResponseCode();
						if (responseCode < 400 && responseCode >= 200) {
							output = new ByteArrayOutputStream(
									connection.getContentLength());
							byte[] temp = new byte[1024];
							int size;
							while ((size = is.read(temp)) > 0) {
								output.write(temp, 0, size);
							}
							output.flush();
							byte[] buf = output.toByteArray();
							mImageCache.set(request.url, buf);
							is.close();
						} else {
							connection.disconnect();
						}

					} catch (ClientProtocolException e) {
						e.printStackTrace();
					} catch (Throwable e) {
						e.printStackTrace();
					} finally {
						if (connection != null) {
							connection.disconnect();
						}
						if (output != null) {
							try {
								output.close();
							} catch (IOException e) {
								e.printStackTrace();
							}
						}
					}
				}
				synchronized (ImageLoader.this) {
					TagObject[] objs = request.objs;
					if (objs != null) {
						for (TagObject obj : objs) {
							synchronized (mImageCache) {
								image = mImageCache.getImage(request.url,
										obj.options, request.activity);
							}
							if (image != null) {
								obj.listener.onSuccess(request.activity,
										request.url, image, obj.tag);
							} else {
								obj.listener.onError(request.activity,
										request.url, obj.tag);
							}
						}
					}
					request.objs = null;
					mCurrentRequest = null;
				}
				image = null;
			}
		}
	};

	private HttpURLConnection getConnection(String url)
			throws MalformedURLException, IOException {
		HttpURLConnection conn = null;
		String proxyStr = HttpUtil.getProxy();
		if (proxyStr != null) {
			String host = null;
			String path = null;
			int hostIndex = "http://".length();
			int pathIndex = url.indexOf('/', hostIndex);
			if (pathIndex < 0) {
				host = url.substring(hostIndex);
				path = "";
			} else {
				host = url.substring(hostIndex, pathIndex);
				path = url.substring(pathIndex);
			}
			conn = (HttpURLConnection) new URL("http://" + proxyStr + path)
					.openConnection();
			conn.setRequestProperty("X-Online-Host", host);
		} else {
			conn = (HttpURLConnection) new URL(url).openConnection();
		}
		// conn.setDoOutput(true);
		conn.setDoInput(true);
		return conn;
	}

	private Bitmap getImageFromBuffer(byte[] buf, String tag) {
		try {
			return BitmapFactory.decodeByteArray(buf, 0, buf.length);
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return null;
	}

	// 设置当前模块
	public synchronized void setCurrentActivity(String activity) {
		if (activity == null) {
			return;
		}
		mCurrentActivity = activity;
		start();
	}

	private void start() {
		synchronized (mLock) {
			if (mRunning) {
				return;
			}
			if (mThread == null) {
				mRunning = true;
				mThread = new Thread(mWork);
				mThread.start();
			} else {
				try {
					mLock.notify();
				} catch (Exception e) {
				}
			}
		}
	}

	// 暂停模块的所有请求
	public synchronized void pause(String activity) {
		if (mCurrentActivity != null && mCurrentActivity.equals(activity)) {
			mCurrentActivity = null;
		}
	}

	public synchronized void cancel(String url, ImageLoaderListener listener) {
		cancel(GLOBAL_ACTIVITY, url, listener);
	}

	// 取消模块的某个请求
	public synchronized void cancel(String activity, String url,
			ImageLoaderListener listener) {
		if (activity == null || url == null || listener == null) {
			return;
		}
		ImageRequest tempR = null;
		boolean temp = false;
		List<ImageRequest> requests = null;
		if (activity.equals(mCurrentActivity) && mCurrentRequest != null
				&& url.equals(mCurrentRequest.url)) {
			tempR = mCurrentRequest;
		} else {
			requests = mRequests.get(activity);
			if (requests == null) {
				return;
			}
			for (ImageRequest r : requests) {
				if (r.url.equals(url)) {
					tempR = r;
					break;
				}
			}
		}
		if (tempR != null) {
			TagObject[] objs = tempR.objs;
			if (objs != null) {
				for (TagObject obj : objs) {
					if (obj.listener == listener) {
						temp = true;
						try {
							obj.listener.onCancel(activity, tempR.url, obj.tag);
						} catch (Exception e) {
						}
						break;
					}
				}
			}
		}
		if (temp) {
			if (tempR.objs.length == 1) {
				if (requests != null) {
					requests.remove(tempR);
					if (requests.size() == 0) {
						mRequests.remove(activity);
					}
				}
			} else {
				tempR.removeListener(listener);
			}
		}
	}

	// 取消模块的所有请求
	public synchronized void cancel(String activity) {
		List<ImageRequest> requests = mRequests.get(activity);
		if (requests == null) {
			return;
		}
		for (ImageRequest r : requests) {
			TagObject[] objs = r.objs;
			if (objs != null) {
				for (TagObject obj : objs) {
					try {
						obj.listener.onCancel(activity, r.url, obj.tag);
					} catch (Exception e) {
					}
				}
			}
		}
		requests.clear();
	}

	/**
	 * 在全局活动里面加入任务
	 * 
	 * @param url
	 * @param listener
	 */
	public void asyncLoadImage(String url, ImageLoaderListener listener,
			ImageOptions options) {
		asyncLoadImage(GLOBAL_ACTIVITY, url, listener, options);
	}

	public void asyncLoadImage(String activity, String url,
			ImageLoaderListener listener, ImageOptions options) {
		asyncLoadImage(activity, url, listener, options, null);
	}

	/**
	 * 在全局活动里面加入任务
	 * 
	 * @param url
	 * @param listener
	 * @param tag
	 */
	public synchronized void asyncLoadImage(String url,
			ImageLoaderListener listener, ImageOptions options, Object tag) {
		asyncLoadImage(GLOBAL_ACTIVITY, url, listener, options, tag);
	}

	/**
	 * 异步加载图片
	 * 
	 * @param activity
	 *            模块
	 * @param url
	 * @param listener
	 */
	public synchronized void asyncLoadImage(String activity, String url,
			ImageLoaderListener listener, ImageOptions options, Object tag) {
		if (url == null || activity == null || listener == null) {
			throw new RuntimeException();
		}
		Bitmap image = null;
		synchronized (mImageCache) {
			image = mImageCache.getImage(url, options, TAG + " url:" + url);
		}
		if (image != null) {
			listener.onSuccess(activity, url, image, tag);
			return;
		}
		List<ImageRequest> requests = mRequests.get(activity);
		if (requests == null) {
			requests = new ArrayList<ImageLoader.ImageRequest>();
			mRequests.put(activity, requests);
		}
		ImageRequest request = null;
		if (mCurrentRequest != null
				&& mCurrentRequest.activity.equals(mCurrentActivity)
				&& url.equals(mCurrentRequest.url)) {
			request = mCurrentRequest;
		} else {
			for (ImageRequest r : requests) {
				if (url.equals(r.url)) {
					request = r;
					break;
				}
			}
		}
		if (request == null) {
			request = new ImageRequest();
			request.url = url;
			requests.add(request);
		}
		request.addListener(listener, options, tag);
		if (!mRunning) {
			boolean start = activity.equals(mCurrentActivity);
			if (!start) {
				List<ImageRequest> rs = mRequests.get(GLOBAL_ACTIVITY);
				if (rs != null && rs.size() > 0) {
					start = true;
				}
			}
			if (start) {
				start();
			}
		}
	}

	public synchronized void saveCache() {
		mImageCache.saveCache();
	}

	public class ImageCache {
		private File cacheFile;
		public String path;
		private FileCache fileCache;
		// 用于缓存用过的图片
		public WeakHashMap<String, Bitmap> mImages = new WeakHashMap<String, Bitmap>(
				100);

		private ImageCache() {
			initFile();
		}

		private void initFile() {
			if (fileCache == null) {
				String cachePath = SysUtil.getExternalStoragePath()+KidConfig.BITMAP_CACHE_NEW;
				if (cachePath != null) {
					
					path = cachePath;
					Log.d("FILE", path);
					cacheFile = new File(path);
					if (!cacheFile.exists()) {
						cacheFile.mkdirs();
					}
				} else {
					return;
				}
				fileCache = new FileCache(path);
			}
		}

		public synchronized boolean set(String url, byte[] data) {
			initFile();
			if (path == null || cacheFile == null)
				return false;
			String temp = url;
			url = processImageUrl(url);
			File f = new File(path + url);
			try {
				f.delete();
				f.createNewFile();
				FileOutputStream fos = new FileOutputStream(f);
				fos.write(data);
				fos.close();
				cache(url);
				return true;
			} catch (IOException e) {
				e.printStackTrace();
				// 如果失败保存到缓存里
				Bitmap image = getImageFromBuffer(data, "");
				if (image != null) {
					mImages.put(temp, image);
				}
			}
			return false;
		}

		private void cache(String fileName) {
			initFile();
			fileCache.putFile(fileName);
		}

		public void saveCache() {
			initFile();
			fileCache.save();
		}

		public Bitmap getImage(String url, ImageOptions options, String tag) {
			initFile();
			if (path == null || cacheFile == null)
				return null;
			String key = url;
			// 如果设置图片选项
			if (options != null
					&& (options.getWidth() != ImageOptions.SIZE_ORIGINAL || options
							.getHeight() != ImageOptions.SIZE_ORIGINAL)) {
				key += "w:" + options.getWidth() + ",h:" + options.getHeight();
			}
			// 从缓存查找
			if (mImages.containsKey(key)) {
				Bitmap image = mImages.get(key);
				if (image != null) {
					return image;
				}
			}
			// 从缓存中查找原始图片
			if (!TextUtils.equals(key, url) && mImages.containsKey(url)) {
				Bitmap image = mImages.get(url);
				if (image != null) {
					return image;
				}
			}
			url = processImageUrl(url);
			String filePath = path + url;
			Bitmap image = ImageUtil.decodeFile(filePath, options, tag);
			mImages.put(key, image);
			return image;
		}

		public byte[] get(String url) {
			initFile();
			if (path == null || cacheFile == null)
				return null;
			url = processImageUrl(url);
			File f = new File(path + url);
			if (f.exists()) {
				FileInputStream fis = null;
				try {
					fis = new FileInputStream(f);

					byte[] b = new byte[fis.available()];
					fis.read(b);
					fis.close();
					cache(url);
					return b;
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (Throwable e) {
					e.printStackTrace();
				} finally {
					if (fis != null)
						try {
							fis.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
				}
			}
			return null;
		}

		private String processImageUrl(String url) {
			String fileName = url;
			String result = MD5.Md5(fileName);
			return result;
		}

		public void delete(String url) {
			initFile();
			if (path == null) {
				return;
			}
			url = processImageUrl(url);
			File file = new File(path + url);
			if (file.exists()) {
				file.delete();
			}
		}

		public void clear() {
			initFile();
			if (cacheFile == null) {
				return;
			}
			File[] files = cacheFile.listFiles();
			for (File f : files) {
				f.delete();
			}
		}
	}

	private class TagObject {
		private ImageLoaderListener listener;
		private Object tag;
		private ImageOptions options;
	}

	private class ImageRequest {
		private String url;
		private String activity;
		private TagObject[] objs;

		public void addListener(ImageLoaderListener listener,
				ImageOptions options, Object tag) {
			TagObject obj = new TagObject();
			obj.listener = listener;
			obj.tag = tag;
			obj.options = options;
			if (objs == null) {
				objs = new TagObject[] { obj };
				return;
			}
			int count = objs.length;
			TagObject[] temp = new TagObject[count + 1];
			System.arraycopy(objs, 0, temp, 0, count);
			temp[count] = obj;
			objs = temp;
		}

		public void removeListener(ImageLoaderListener listener) {
			if (listener == null) {
				return;
			}
			int index = -1;
			int count = objs.length;
			for (int i = 0; i < count; i++) {
				if (objs[i].listener == listener) {
					index = i;
					break;
				}
			}
			if (index == -1) {
				return;
			}
			if (count == 1) {
				objs = null;
			} else {
				TagObject[] temp = new TagObject[count - 1];
				System.arraycopy(objs, 0, temp, 0, index);
				System.arraycopy(objs, index + 1, temp, index, count - index
						- 1);
				objs = temp;
			}
		}
	}

	public interface ImageLoaderListener {
		public void onSuccess(String activity, String url, Bitmap image,
				Object tag);

		public void onError(String activity, String url, Object tag);

		public void onCancel(String activity, String url, Object tag);
	}
}
